import lombok.extern.slf4j.Slf4j;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author： pang-yun
 * @date： 2021-11-15 14:12
 * 功能目的 ：用于
 */

@Slf4j
public class Pool {
    public static void main(String[] args) {
        ThreadPool threadPool = new ThreadPool(2,10);
        for (int i = 0; i < 5; i++) {
            int j=i;
            threadPool.execute(()->{
                log.info("{}",j);
            });
        }
    }

}

@Slf4j
class ThreadPool {
    private BlockedQueue<Runnable> taskDeque;
    private HashSet<Worker> works = new HashSet<>();
    private int coreSize;

    public ThreadPool(int coreSize, int capacity) {
        this.coreSize = coreSize;
        this.taskDeque= new BlockedQueue<>(capacity);
    }


    public void execute(Runnable task) {
        synchronized (this) {
            if (works.size() < coreSize) {
                Worker worker = new Worker(task);
                works.add(worker);
                worker.start();
            } else {
                taskDeque.add(task);
            }
        }
    }


    class Worker extends Thread {
        private Runnable task;

        public Worker(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            while (task != null || (task = taskDeque.take()) != null) {
                try {
                    log.info("正在执行 {}",task);
                    task.run();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    task = null;
                }
            }
            synchronized (this) {
                works.remove(this);
            }
        }
    }
}


class BlockedQueue<T> {
    private Deque<T> deque = new ArrayDeque<>();
    private ReentrantLock lock = new ReentrantLock();
    private Condition fullWaitSet = lock.newCondition();
    private Condition emptyWaitSet = lock.newCondition();
    private int coreSize;

    public BlockedQueue(int coreSize) {
        this.coreSize = coreSize;
    }

    // 获取大小
    public int getDequeSize() {
        lock.lock();
        try {
            return deque.size();
        } finally {
            lock.unlock();
        }
    }

    // 阻塞获取
    public T take() {
        lock.lock();
        try {
            while (deque.isEmpty()) {
                try {
                    emptyWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T first = deque.removeFirst();
            fullWaitSet.signalAll();
            return first;
        } finally {
            lock.unlock();
        }
    }

    // 阻塞添加
    public void add(T t) {
        lock.lock();
        try {
            while (getDequeSize() == coreSize) {
                try {
                    fullWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            deque.addLast(t);
            emptyWaitSet.signalAll();

        } finally {
            lock.unlock();
        }
    }
}